package com.cencat.framework.security.service;

import com.cencat.framework.security.model.LoginUser;
import com.cencat.framework.security.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * Token服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TokenService {
    
    private final JwtUtil jwtUtil;
    private final RedisTemplate<String, Object> redisTemplate;
    
    private static final String LOGIN_USER_KEY = "login_tokens:";
    private static final long EXPIRE_TIME = 7200; // 2小时
    
    /**
     * 创建令牌
     */
    public String createToken(LoginUser loginUser) {
        // 生成JWT令牌
        String token = jwtUtil.generateToken(loginUser);
        
        // 设置用户唯一标识
        String userKey = getTokenKey(loginUser.getUserId());
        
        // 缓存用户信息
        redisTemplate.opsForValue().set(userKey, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);
        
        // 缓存令牌与用户ID的映射
        String tokenKey = getTokenKey(token);
        redisTemplate.opsForValue().set(tokenKey, loginUser.getUserId(), EXPIRE_TIME, TimeUnit.SECONDS);
        
        log.debug("创建令牌成功: userId={}, username={}", loginUser.getUserId(), loginUser.getUsername());
        
        return token;
    }
    
    /**
     * 获取登录用户信息
     */
    public LoginUser getLoginUser(String token) {
        if (!jwtUtil.validateToken(token)) {
            return null;
        }
        
        try {
            Long userId = jwtUtil.getUserIdFromToken(token);
            if (userId == null) {
                return null;
            }
            
            String userKey = getTokenKey(userId);
            LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(userKey);
            
            if (loginUser != null) {
                // 验证令牌有效性
                verifyToken(loginUser);
            }
            
            return loginUser;
        } catch (Exception e) {
            log.error("获取登录用户信息失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 删除用户缓存信息
     */
    public void deleteLoginUser(Long userId) {
        if (userId != null) {
            String userKey = getTokenKey(userId);
            redisTemplate.delete(userKey);
            log.debug("删除用户缓存: userId={}", userId);
        }
    }
    
    /**
     * 验证令牌有效期
     */
    public void verifyToken(LoginUser loginUser) {
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        
        if (expireTime - currentTime <= 10 * 60 * 1000) { // 10分钟内过期
            // 刷新令牌
            refreshToken(loginUser);
        }
    }
    
    /**
     * 刷新令牌
     */
    public void refreshToken(LoginUser loginUser) {
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(loginUser.getLoginTime() + EXPIRE_TIME * 1000);
        
        // 更新缓存
        String userKey = getTokenKey(loginUser.getUserId());
        redisTemplate.opsForValue().set(userKey, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);
        
        log.debug("刷新令牌: userId={}", loginUser.getUserId());
    }
    
    /**
     * 设置用户身份信息
     */
    public void setLoginUser(LoginUser loginUser) {
        if (loginUser != null && loginUser.getUserId() != null) {
            String userKey = getTokenKey(loginUser.getUserId());
            redisTemplate.opsForValue().set(userKey, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);
        }
    }
    
    /**
     * 删除令牌
     */
    public void deleteToken(String token) {
        if (token == null) {
            return;
        }
        
        try {
            Long userId = jwtUtil.getUserIdFromToken(token);
            if (userId != null) {
                // 删除用户缓存
                deleteLoginUser(userId);
                
                // 删除令牌映射
                String tokenKey = getTokenKey(token);
                redisTemplate.delete(tokenKey);
                
                log.debug("删除令牌: token={}, userId={}", token, userId);
            }
        } catch (Exception e) {
            log.error("删除令牌失败: {}", e.getMessage());
        }
    }
    
    /**
     * 获取令牌缓存key
     */
    private String getTokenKey(String token) {
        return LOGIN_USER_KEY + token;
    }
    
    /**
     * 获取用户缓存key
     */
    private String getTokenKey(Long userId) {
        return LOGIN_USER_KEY + userId;
    }
    
    /**
     * 获取登录用户ID
     */
    public Long getLoginUserId() {
        try {
            // 从安全上下文中获取当前用户
            LoginUser loginUser = getCurrentLoginUser();
            return loginUser != null ? loginUser.getUserId() : null;
        } catch (Exception e) {
            log.error("获取登录用户ID失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 获取当前登录用户
     */
    public LoginUser getCurrentLoginUser() {
        try {
            // 从安全上下文中获取认证信息
            org.springframework.security.core.Authentication authentication = 
                org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication();
            
            if (authentication != null && authentication.getPrincipal() instanceof LoginUser) {
                return (LoginUser) authentication.getPrincipal();
            }
            
            return null;
        } catch (Exception e) {
            log.error("获取当前登录用户失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 检查用户是否登录
     */
    public boolean isLogin() {
        return getCurrentLoginUser() != null;
    }
    
    /**
     * 检查用户是否拥有指定权限
     */
    public boolean hasPermission(String permission) {
        LoginUser loginUser = getCurrentLoginUser();
        return loginUser != null && loginUser.hasPermission(permission);
    }
    
    /**
     * 检查用户是否拥有任一权限
     */
    public boolean hasAnyPermission(String... permissions) {
        LoginUser loginUser = getCurrentLoginUser();
        return loginUser != null && loginUser.hasAnyPermission(permissions);
    }
    
    /**
     * 检查用户是否拥有所有权限
     */
    public boolean hasAllPermissions(String... permissions) {
        LoginUser loginUser = getCurrentLoginUser();
        return loginUser != null && loginUser.hasAllPermissions(permissions);
    }
}